Flutter / Examples / * Project 30 : News App 1
UI News App
-
Screen 1
UI
1 . API call with async
pubspec.yaml
dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 http: ^1.2.1 cached_network_image: ^3.3.1 main.dart
import 'package:flutter/material.dart'; import 'package:new_app_api/Screen/home_screen.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: NewsHomeScreen(), ); } } model/category_data.dart
import 'new_model.dart'; List getCategories() { // news category list List categories = []; CategoryModel category = CategoryModel(); category.categoryName = "Science"; categories.add(category); category = CategoryModel(); category.categoryName = "Sports"; categories.add(category); category = CategoryModel(); category.categoryName = "Business"; categories.add(category); category = CategoryModel(); category.categoryName = "General"; categories.add(category); category = CategoryModel(); category.categoryName = "Health"; categories.add(category); category = CategoryModel(); category.categoryName = "Entertainment"; categories.add(category); return categories; } model/new_model.dart
class CategoryModel { String? categoryName; CategoryModel({ this.categoryName, }); } class NewsModel { String? title; String? description; String? urlToImage; String? author; String? content; NewsModel({ this.title, this.description, this.urlToImage, this.author, this.content, }); } Services/services.dart
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:new_app_api/model/new_model.dart'; class NewsApi { // for news home screen List dataStore = []; Future getNews() async { Uri url = Uri.parse( "https://newsapi.org/v2/top-headlines?country=us&apiKey=313e712139fc486796d895c700aef894"); var response = await http.get(url); var jsonData = jsonDecode(response.body); if (jsonData["status"] == 'ok') { jsonData["articles"].forEach((element) { if (element['urlToImage'] != null && element['description'] != null && element['author'] != null && element['content'] != null) { NewsModel newsModel = NewsModel( title: element['title'], // name must be same fron api urlToImage: element['urlToImage'], description: element['description'], author: element['author'], content: element['content'], ); dataStore.add(newsModel); } }); } } } class CategoryNews { // for news home screen List dataStore = []; Future getNews(String category) async { Uri url = Uri.parse( "https://newsapi.org/v2/top-headlines?country=us&category=$category&apiKey=313e712139fc486796d895c700aef894"); var response = await http.get(url); var jsonData = jsonDecode(response.body); if (jsonData["status"] == 'ok') { jsonData["articles"].forEach((element) { if (element['urlToImage'] != null && element['description'] != null && element['author'] != null && element['content'] != null) { NewsModel newsModel = NewsModel( title: element['title'], // name must be same fron api urlToImage: element['urlToImage'], description: element['description'], author: element['author'], content: element['content'], ); dataStore.add(newsModel); } }); } } } // for category news // we have used the free news api. for that, first you need to create a account and then login // after that get the api key Screen/category_news.dart
import 'package:flutter/material.dart'; import 'package:new_app_api/Screen/news_detail.dart'; import 'package:new_app_api/Services/services.dart'; import '../model/new_model.dart'; class SelectedCategoryNews extends StatefulWidget { String category; SelectedCategoryNews({super.key, required this.category}); @override State createState() => _SelectedCategoryNewsState(); } class _SelectedCategoryNewsState extends State { List articles = []; bool isLoadin = true; getNews() async { CategoryNews news = CategoryNews(); await news.getNews(widget.category); articles = news.dataStore; setState(() { isLoadin = false; }); } @override void initState() { getNews(); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.blue, foregroundColor: Colors.white, title: Text( widget.category, style: const TextStyle( fontWeight: FontWeight.bold, ), ), ), body: isLoadin ? const Center( child: CircularProgressIndicator(), ) : SingleChildScrollView( child: ListView.builder( itemCount: articles.length, shrinkWrap: true, physics: const ClampingScrollPhysics(), itemBuilder: (context, index) { final article = articles[index]; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => NewsDetail(newsModel: article), ), ); }, child: Container( margin: const EdgeInsets.all(15), child: Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( article.urlToImage!, height: 250, width: 400, fit: BoxFit.cover, ), ), const SizedBox(height: 10), Text( article.title!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), const Divider(thickness: 2), ], ), ), ); }, ), ), ); } } Screen/home_screen.dart
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:new_app_api/Screen/category_news.dart'; import 'package:new_app_api/Screen/news_detail.dart'; import 'package:new_app_api/Services/services.dart'; import 'package:new_app_api/model/category_data.dart'; import '../model/new_model.dart'; class NewsHomeScreen extends StatefulWidget { const NewsHomeScreen({super.key}); @override _NewsHomeScreenState createState() => _NewsHomeScreenState(); } class _NewsHomeScreenState extends State { List articles = []; List categories = []; bool isLoadin = true; getNews() async { NewsApi newsApi = NewsApi(); await newsApi.getNews(); articles = newsApi.dataStore; setState(() { isLoadin = false; }); } @override void initState() { categories = getCategories(); getNews(); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "Flutte News App", style: TextStyle( fontWeight: FontWeight.bold, ), ), ), body: isLoadin ? const Center( child: CircularProgressIndicator(), ) : SingleChildScrollView( child: Column( children: [ // for category selection Container( height: 55, padding: const EdgeInsets.symmetric( horizontal: 15, ), child: ListView.builder( itemCount: categories.length, shrinkWrap: true, scrollDirection: Axis.horizontal, itemBuilder: (context, index) { final category = categories[index]; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SelectedCategoryNews( category: category.categoryName!, ), ), ); }, child: Padding( padding: const EdgeInsets.only(right: 15), child: Container( alignment: Alignment.center, padding: const EdgeInsets.all(15), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Colors.blue), child: Center( child: Text( category.categoryName!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white, ), ), ), ), ), ); }, ), ), // for home screen news ListView.builder( itemCount: articles.length, shrinkWrap: true, physics: const ClampingScrollPhysics(), itemBuilder: (context, index) { final article = articles[index]; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => NewsDetail(newsModel: article), ), ); }, child: Container( margin: const EdgeInsets.all(15), child: Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( article.urlToImage!, height: 250, width: 400, fit: BoxFit.cover, ), ), const SizedBox(height: 10), Text( article.title!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), const Divider(thickness: 2), ], ), ), ); }, ), ], ), ), ); } } Screen/news_detail.dart
import 'package:flutter/material.dart'; import 'package:new_app_api/model/new_model.dart'; class NewsDetail extends StatelessWidget { final NewsModel newsModel; const NewsDetail({super.key, required this.newsModel}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Padding( padding: const EdgeInsets.all(8.0), child: ListView( children: [ Text( newsModel.title!, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, ), ), Row( children: [ const Expanded( child: SizedBox(), ), Expanded( child: Text( "- ${newsModel.author!}", maxLines: 1, )) ], ), const SizedBox(height: 10), Image.network(newsModel.urlToImage!), const SizedBox(height: 10), Text( newsModel.content!, style: const TextStyle( fontSize: 18, ), ), const SizedBox(height: 10), Text( newsModel.description!, style: const TextStyle( fontSize: 18, ), ) ], ), ), ); } }